/*
 *	CHANGE LOG
 * 
 * 01.02.01
 *
 *		10/07/2008 - DW - Added HTML encoding to the UpdateFaq procedure.
 * 
 * 01.02.02
 *
 *		12/27/2008 - DW - Added code to authorize method calls
 */



using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Users;
using DotNetNuke.Modules.FAQs;
using DataProvider=DotNetNuke.Data.DataProvider;

namespace ITCrossing
{
	public class metaPostFAQsProvider : IPublishable
	{
		# region IPublishable Members

		# region Public Properties

		/// <summary>
		/// ProviderKey should be set to the Friendly Name of the module for
		/// which this provider is being implemented.
		/// </summary>
		public string ProviderKey
		{
			get
			{
				return MetaPostServices.GetFriendlyNameFromModuleDefinition("FAQs");
			}
		}

		/// <summary>
		/// ManifestFilePath is the path including the filename to the manifest file used to determine 
		/// the settings available in Windows Live Writer.  An example path might
		/// be /DesktopModules/itcMetaPost/manifests/wlwblog.xml.  See the following URL for 
		/// information regarding what Content can be placed in a WLW manifest file:
		/// http://msdn2.microsoft.com/en-us/library/bb463260.aspx
		/// </summary>
		public string ManifestFilePath
		{
			get { return "/DesktopModules/itcMetaPost/manifests/wlwfaqs.xml"; }
		}

		/// <summary>
		/// LocalizationFilePath is the path including the filename to the 
		/// resource file used by the module to retrieve the error messages
		/// shown to the user (eg. "/DesktopModules/custommodule/App_LocalResources/customfilename")
		/// Note that the filename should not include the file extension.
		/// </summary>
		public string LocalizationFilePath
		{
			get { return "/DesktopModules/itcMetaPost/App_LocalResources/itcMetaPostFAQs"; }
		}

		/// <summary>
		/// OPTIONAL - ImageUploadPath is a property metaPost uses to determine where 
		/// to store the media files (images).  This property should return just a 
		/// section of the path starting from the portal root.  Added to this path will
		/// be the username along with the path 
		/// </summary>
		public string ImageUploadPath
		{
			get
			{
				// This can be overridden with custom implementation if needed.  If
				// overridden, then a message should be placed in the ImagePath column
				// for your provider letting administrators know that administration of
				// the ImagePath is implemented elsewhere.  
				return MetaPostServices.GetProviderImageUploadPath(ProviderKey);
			}
		}

		/// <summary>
		/// AttachmentUploadPath is used to specify the location of attachments added
		/// to a post or page.
		/// </summary>
		public string AttachmentUploadPath
		{
			get
			{
				// For now, we'll just set this to the same as the image upload path
				return MetaPostServices.GetProviderAttachmentUploadPath(ProviderKey);
			}
		}

		/// <summary>
		/// SettingsUserControlPath is for future use.  It will return the path to the
		/// the settings user control for this provider.  
		/// </summary>
		public string SettingsUserControlPath
		{
			get { throw new NotImplementedException(); }
		}

		# endregion

		# region Get Methods
		/// <summary>
		/// The purpose of this procedure is to provide a list of all the modules in a 
		/// given portal to which the currently logged on user has either insert, update
		/// or delete access.  Note, this may not always correspond to an actual module.
		/// For example, with the DNN Blog module provider, a list of blogs is returned
		/// along with URL of where each blog is available within the site.  For the News
		/// Articles module, we return a list of all News Articles modules that have been
		/// added to Tabs throughout the site.
		/// </summary>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		/// <param name="providerKey"></param>
		public ModuleInfoStruct[] GetModulesForUser(UserInfo userInfo, PortalSettings portalSettings, string providerKey)
		{
			return MetaPostServices.GetModulesForUser(
				providerKey, userInfo.UserID, portalSettings.PortalId);

		}

		/// <summary>
		/// GetRecentItems returns a list of the recent items added to the module.  For example, with
		/// the blog module, the list would return all the recent blog entries.  For the Text/HTML provider, 
		/// this method would return a list of the recently added Text/HTML modules in the site.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="numberOfItems"></param>
		/// <param name="requestType">GetRecentItems can be called for a number of reasons.  In Windows Live Writer,
		/// users are able to retrieve a list of recent posts or recent pages.  The requestType parameter is used
		/// to denote whether a list of pages or posts is being requested.  Additionally, WLW may request a list 
		/// of hiearchical pages to show pages when allowing a parent page to be assigned to a new page.  The values for this enum
		/// are RecentPosts, RecentPages and RecentPagesHiearchical.</param>
		/// <param name="providerKey"></param>
		/// <returns></returns>		
		public Item[] GetRecentItems(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, int numberOfItems, RecentItemsRequestType requestType, string providerKey)
		{

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, moduleLevelId,
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			
			
			// Get the actual ModuleId since we're tracking the TabModuleId in the moduleLevelId parameter
			int moduleId = MetaPostServices.GetModuleIdByTabModuleId(Convert.ToInt32(moduleLevelId));

			List<Item> itemArray = new List<Item>();

			FAQsController faqController = new FAQsController();
			ArrayList faqsArrayList = faqController.ListFAQ(moduleId, 0);

			if (faqsArrayList.Count > 0)
			{
				int count = 0;
				foreach (FAQsInfo faqInfo in faqsArrayList)
				{
					Item item = new Item();
					item.ItemId = faqInfo.ItemId.ToString();
					item.Title = HtmlUtils.StripTags(HttpUtility.HtmlDecode(faqInfo.Question), false);
					item.Content = HttpUtility.HtmlDecode(faqInfo.Answer);
					item.DateCreated = faqInfo.CreatedDate;
					itemArray.Add(item);
					count++;
					if (count >= numberOfItems) break;
				}
			}
			else
			{
				throw new MetaPostException("RecentPostsError",
											"There are no FAQs associated with this user account.  Please enter a user account which has been associated with a blog.");
			}

			return itemArray.ToArray();
		}

		/// <summary>
		/// GetItem is used to retrieve a specific item, which may be a page or a post if your module supports
		/// both concepts.  In cases where a module supports both pages and posts, a concept made available in 
		/// Windows Live Writer, but not in Word 2007 or in many other publishing clients, the itemType parameter 
		/// can be used to distinguish between when this method is being called to add a page or a post.  If your 
		/// provider doesn't support a distinction between pages and posts, then simply ignore the itemType parameter.
		/// </summary>
		/// <param name="itemId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="itemType"></param>
		/// <returns></returns>
		public Item GetItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{
			Item item = new Item();

			int moduleId = 0;

			moduleId = Convert.ToInt32(GetModuleIdFromItemId(itemId, portalSettings.PortalId));

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.DnnModuleId, moduleId.ToString(),
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			FAQsController faqController = new FAQsController();
			FAQsInfo faqsInfo = faqController.GetFAQ(Convert.ToInt32(itemId), moduleId);

			bool titleContainsHtml = MetaPostServices.ContainsHtml(HttpUtility.HtmlDecode(faqsInfo.Question));
			if (titleContainsHtml)
			{
				item.Title = MetaPostServices.GetString("TitleContainsHtml", "Titles which contain HTML are managed as a split post.", LocalizationFilePath, portalSettings.DefaultLanguage);
				item.Content = HttpUtility.HtmlDecode(faqsInfo.Question)
							   + "<!--more-->"
							   + HttpUtility.HtmlDecode(faqsInfo.Answer);
			}
			else
			{
				item.Title = HttpUtility.HtmlDecode(faqsInfo.Question);
				item.Content = HttpUtility.HtmlDecode(faqsInfo.Answer);

			}


			item.DateCreated = faqsInfo.CreatedDate;
			item.ItemId = faqsInfo.ItemId;

			// Use the UserController to look up a user's name
			UserController userController = new UserController();
			UserInfo dnnUserInfo = userController.GetUser(portalSettings.PortalId, Convert.ToInt32(faqsInfo.CreatedByUser));

			item.AuthorId = (dnnUserInfo == null) ? string.Empty : dnnUserInfo.DisplayName;

			return item;
		}

		# endregion 

		# region Add, Edit and Delete Methods

		/// <summary>
		/// EditItem is called to edit either a page or a post.  The difference
		/// between the two is denoted in a property of the Item struct (ItemType).
		/// An additional property of the Item struct that may be important to the 
		/// implementation of the EditItem method is the Publish property.  This is 
		/// set to true when the item should be published.  The default setting of 
		/// false denotes that the item may be saved as a draft.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="item"></param>
		/// <returns></returns>
		public string NewItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.ModuleLevelId, moduleLevelId,
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			List<string> images = MetaPostServices.GetImageListFromItem(ref item);
			
			// Get the actual ModuleId since we're tracking the TabModuleId in the moduleLevelId parameter
			int moduleId = MetaPostServices.GetModuleIdByTabModuleId(Convert.ToInt32(moduleLevelId));

			# region Style Detection Code

			// This code is only needed in order to aid in style detection for the FAQs module.  Since it
			// doesn't show the answer in the default view of the page, WLW can't see the answer and can't 
			// download the styles.  We'll trick WLW into seeing the answer.  
			// NOTE:  This code is only needed in order to workaround the fact that the FAQs module doesn't
			// initially show the answer.
			if (item.StyleDetectionPost)
			{
				//
				// Decided to remove this since I don't want to be messing anyone's data up.
				//
				//ModuleController moduleController = new ModuleController();
				//ModuleInfo moduleInfo =
				//    moduleController.GetModule(Convert.ToInt32(moduleId), Null.NullInteger, false);
				//Hashtable settings
				//    = PortalSettings.GetModuleSettings(moduleId);
				//MetaPostServices.SetTempStyleValue(userInfo.UserID, 
				//    "FaqEnableAjax", 
				//    settings["FaqEnableAjax"] as string);
				//MetaPostServices.SetTempStyleValue(userInfo.UserID, 
				//    "FaqQuestionTemplate", 
				//    settings["FaqQuestionTemplate"] as string);
				//// Set the Module Settings to value which will enable style detection
				//DataProvider.Instance().UpdateModuleSetting(moduleId, "FaqEnableAjax", "False");
				//string newQuestionTemplate = settings["FaqQuestionTemplate"] as string;
				//if (string.IsNullOrEmpty(newQuestionTemplate))
				//{
				//    newQuestionTemplate = "<div Class=\"Normal\"><b>Q[INDEX]. [QUESTION]</b></div>"
				//        + "</a>\n<div Class=\"Normal\" Style=\"padding: 5px;\"><b>Answer:</b> [ANSWER]</div><a href=\"tempstyle\">"; 
				//}
				//else
				//{
				//    newQuestionTemplate += "</a>\n<div Class=\"Normal\" Style=\"padding: 5px;\"><b>Answer:</b> [ANSWER]</div><a href=\"tempstyle\">";
				//}

				//DataProvider.Instance().UpdateModuleSetting(moduleId, "FaqQuestionTemplate", newQuestionTemplate);

				// We will come back and restore these values in the delete operation.
			}
			

			# endregion

			// Tell the UpdateFaq procedure that we're adding a new FAQ.
			item.ItemId = "-1";
			int faqId = UpdateFaq(item, moduleId, userInfo);

			MetaPostServices.SaveItemImages(faqId, images, ProviderKey, portalSettings, userInfo.UserID);

			return faqId.ToString();
		}

		/// <summary>
		/// EditItem is called to edit either a page or a post.  The difference
		/// between the two is denoted in a property of the Item struct (ItemType).
		/// An additional property of the Item struct that may be important to the 
		/// implementation of the EditItem method is the Publish property.  This is 
		/// set to true when the item should be published.  The default setting of 
		/// false denotes that the item may be saved as a draft.
		///
		/// It's important to note that when Windows Live Writer sends the information 
		///		for a post edit, the moduleLevelId is not passed.  For implementation of 
		///		this procedure in providers which do not support pages, the moduleLevelId 
		///		should be ignored and attempts to get the moduleId can be made by calling
		///		GetModuleIdFromItemId or a similar private procedure.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="item"></param>
		/// <returns></returns>
		public bool EditItem(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings, Item item)
		{

			List<string> images = MetaPostServices.GetImageListFromItem(ref item);

			// Get the actual ModuleId 
			string moduleId = GetModuleIdFromItemId((string)item.ItemId, portalSettings.PortalId);

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.DnnModuleId, moduleId.ToString(),
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			item.ItemId = item.ItemId;

			UpdateFaq(item, Convert.ToInt32(moduleId), userInfo);

			MetaPostServices.SaveItemImages(Convert.ToInt32(item.ItemId), images, ProviderKey, portalSettings, userInfo.UserID);

			return true;
		}

		/// <summary>
		/// DeleteItem is used to delete either a page or a post.  The difference between the two is noted 
		/// in the itemType parameter which is an enumeration set to either Page or Post.
		/// </summary>
		/// <param name="itemId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <param name="itemType"></param>
		/// <returns></returns>		
		public bool DeleteItem(string itemId, UserInfo userInfo, PortalSettings portalSettings, ItemType itemType)
		{
			string moduleId = GetModuleIdFromItemId(itemId, portalSettings.PortalId);

			// Authorize user for method call
			MetaPostServices.AuthorizeUser(AuthorizationType.DnnModuleId, moduleId.ToString(),
							   GetModulesForUser(userInfo, portalSettings, ProviderKey));			

			# region Code for Cleaning up After Temporary Style Posts
			//
			// Removed to as not to change the data behind the scenes.  
			//
			//// The following code should only be executed if cleaning up after WLW
			//// tries to create a temporary style post.
			
			//string faqEnableAjax = MetaPostServices.GetTempStyleValue(userInfo.UserID, "FaqEnableAjax");
			//if (!string.IsNullOrEmpty(faqEnableAjax))
			//{
			//    // Retrieve the ModuleId
			//    string faqQuestionTemplate =
			//        MetaPostServices.GetTempStyleValue(userInfo.UserID, "FaqQuestionTemplate");
			//    DataProvider.Instance().UpdateModuleSetting(Convert.ToInt32(moduleId), "FaqEnableAjax", faqEnableAjax);
			//    DataProvider.Instance().UpdateModuleSetting(Convert.ToInt32(moduleId), "FaqQuestionTemplate", faqQuestionTemplate);
			//}
			# endregion

			FAQsController faqController = new FAQsController();
			faqController.DeleteFAQ(Convert.ToInt32(itemId), Convert.ToInt32(moduleId));

			return true;
		}

		# endregion

		# region Category Related Procedures

		/// <summary>
		/// GetCategories retrieves a list of categories for a particular module.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>		
		public ItemCategoryInfo[] GetCategories(string moduleLevelId, UserInfo userInfo, PortalSettings portalSettings)
		{
			// Get the actual ModuleId since we're tracking the TabModuleId in the moduleLevelId parameter
			int moduleId = MetaPostServices.GetModuleIdByTabModuleId(Convert.ToInt32(moduleLevelId));

			List<ItemCategoryInfo> catInfoList = new List<ItemCategoryInfo>();

			FAQsController faqController = new FAQsController();
			
			// Get the categories from the controller
			ArrayList faqCategories = faqController.ListCategories(moduleId);
				
			foreach (CategoryInfo faqCat in faqCategories)
			{
				ItemCategoryInfo catInfo = new ItemCategoryInfo();
				catInfo.CategoryId = faqCat.FaqCategoryId;
				catInfo.CategoryName = faqCat.FaqCategoryName;
				catInfo.Description = faqCat.FaqCategoryName;
				catInfo.HtmlUrl = "";
				catInfo.RssUrl = "";
				catInfo.ParentId = 0;
				catInfoList.Add(catInfo);
			}
			return catInfoList.ToArray();
		}

		public bool SetItemCategories(string itemId, ItemCategory[] itemCategories, UserInfo userInfo,
		                        PortalSettings portalSettings)
		{
			// Not yet implemented.
			return true;
		}

		public ItemCategory[] GetItemCategories(string itemId, UserInfo userInfo,
		                                        PortalSettings portalSettings)
		{
			List<ItemCategory> itemCategories = new List<ItemCategory>();
			int moduleId = Convert.ToInt32(GetModuleIdFromItemId(itemId, portalSettings.PortalId));

			FAQsController faqController = new FAQsController();
			FAQsInfo faqsInfo = faqController.GetFAQ(Convert.ToInt32(itemId), moduleId);

			if (faqsInfo.CategoryId != -1)
			{
				ItemCategory ic;
				CategoryInfo catInfo = faqController.GetCategory(faqsInfo.CategoryId, moduleId);

				ic = new ItemCategory();
				ic.CategoryId = faqsInfo.CategoryId.ToString();
				ic.CategoryName = catInfo.FaqCategoryName;
				itemCategories.Add(ic);
			}

			return itemCategories.ToArray();
		}

		/// <summary>
		/// Used to add a new category for modules which support this feature.
		/// </summary>
		/// <param name="moduleLevelId"></param>
		/// <param name="userInfo"></param>
		/// <param name="portalSettings"></param>
		/// <returns></returns>
		public int NewCategory(string moduleLevelId, NewItemCategory category, UserInfo userInfo, PortalSettings portalSettings)
		{
			int categoryId = 0;
			// Check first to see if the user should have the ability to add Categories

			ModuleController moduleController = new ModuleController();
			//ModuleInfo moduleInfo =
			//    moduleController.getm(portalSettings.PortalId, moduleName);
			//bool bHasAdminRights = PortalSecurity.IsInRoles(_moduleConfiguration.AuthorizedEditRoles);
			//Dim blnHasModuleEditPermissions As Boolean = PortalSecurity.IsInRoles(_moduleConfiguration.AuthorizedEditRoles)
			throw new MetaPostException("FeatureNotImplemented",
										"This feature is currently not implemented.");

			return categoryId;
		}

		# endregion

		#endregion

		# region Private Procedures Specific to Text/HTML Module

		/// <summary>
		/// GetModuleIdFromItemId is needed for the FAQs provider for the GetItem method which calls it.
		/// </summary>
		/// <param name="itemId"></param>
		/// <returns></returns>
		/// <param name="portalId"></param>
		private string GetModuleIdFromItemId(string itemId, int portalId)
		{
			int moduleId;
			// Get the moduleLevelId from the itemId
			object[] methodParams = { itemId };
			string SQL = "itcmetapost_faqs_get_moduleid_by_itemid";
			moduleId = (int)DataProvider.Instance().ExecuteScalar(SQL, methodParams);
			return moduleId.ToString();
			return null;
		}

		/// <summary>
		/// UpdateFaq is the procedure which handles updating the database with the
		/// changes made to the FAQ entry.
		/// </summary>
		/// <param name="item"></param>
		/// <param name="moduleId"></param>
		/// <param name="userInfo"></param>
		/// <returns></returns>
		private int UpdateFaq(Item item, int moduleId, UserInfo userInfo)
		{
			FAQsController faqController = new FAQsController();
			CategoryInfo selectedCatInfo = null;
			int faqId = 0;

			// Check to see if we have a category selected
			if (item.Categories.Length > 0)
			{
				string selectedCategory = item.Categories[0];
				ArrayList categories = faqController.ListCategories(moduleId);
				foreach (CategoryInfo cat in categories)
				{
					if (cat.FaqCategoryName == selectedCategory) selectedCatInfo = cat;
				}
			}

			FAQsInfo faqInfo = new FAQsInfo();

			faqInfo.ItemId = (item.ItemId.ToString() == "-1") ? -1 : Convert.ToInt32(item.ItemId);
			if (selectedCatInfo != null) faqInfo.CategoryId = selectedCatInfo.FaqCategoryId;
			faqInfo.Question = (string.IsNullOrEmpty(item.ExtendedContent))
								? item.Title
								: item.Content;
			faqInfo.Answer = (string.IsNullOrEmpty(item.ExtendedContent))
								? item.Content
								: item.ExtendedContent;
			faqInfo.CreatedByUser = userInfo.UserID.ToString();
			faqInfo.ViewCount = 0;
			faqInfo.CreatedDate = DateTime.Now;
			faqInfo.DateModified = DateTime.Now;
			faqInfo.ModuleId = Convert.ToInt32(moduleId);

			// Make sure to HTML encode the Question and Answer
			faqInfo.Question = HttpUtility.HtmlEncode(faqInfo.Question);
			faqInfo.Answer = HttpUtility.HtmlEncode(faqInfo.Answer);

			if (faqInfo.ItemId == -1)
			{
				faqId = faqController.AddFAQ(faqInfo);	
			}
			else
			{
				faqController.UpdateFAQ(faqInfo);
				faqId = faqInfo.ItemId;
			}
			
			return faqId;
		}

		# endregion

	}
}